home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1865 / 1865.xpi / components / AdblockPlus.js
Text File  |  2010-01-07  |  14KB  |  550 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Adblock Plus.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Wladimir Palant.
  18.  * Portions created by the Initial Developer are Copyright (C) 2006-2007
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *
  23.  * ***** END LICENSE BLOCK ***** */
  24.  
  25. /*
  26.  * Constants / Globals
  27.  */
  28.  
  29. const Cc = Components.classes;
  30. const Ci = Components.interfaces;
  31. const Cr = Components.results;
  32. const Cu = Components.utils;
  33.  
  34. const Node = Ci.nsIDOMNode;
  35. const Element = Ci.nsIDOMElement;
  36. const Window = Ci.nsIDOMWindow;
  37.  
  38. const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
  39. const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  40. const versionComparator = Cc["@mozilla.org/xpcom/version-comparator;1"].createInstance(Ci.nsIVersionComparator);
  41. var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  42. var windowWatcher= Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
  43. try
  44. {
  45.     var headerParser = Cc["@mozilla.org/messenger/headerparser;1"].getService(Ci.nsIMsgHeaderParser);
  46. }
  47. catch(e)
  48. {
  49.     headerParser = null;
  50. }
  51.  
  52. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  53.  
  54. /**
  55.  * Application startup/shutdown observer, triggers init()/shutdown() methods in abp object.
  56.  * @constructor
  57.  */
  58. function Initializer() {}
  59. Initializer.prototype =
  60. {
  61.     classDescription: "Adblock Plus initializer",
  62.     contractID: "@adblockplus.org/abp/startup;1",
  63.     classID: Components.ID("{d32a3c00-4ed3-11de-8a39-0800200c9a66}"),
  64.     _xpcom_categories: [{ category: "app-startup", service: true }],
  65.  
  66.     QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
  67.  
  68.     observe: function(subject, topic, data)
  69.     {
  70.         switch (topic)
  71.         {
  72.             case "app-startup":
  73.                 let observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  74.                 observerService.addObserver(this, "profile-after-change", true);
  75.                 observerService.addObserver(this, "quit-application", true);
  76.                 break;
  77.             case "profile-after-change":
  78.                 // delayed init for Fennec
  79.                 let appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
  80.                 if (appInfo.ID != "{a23983c0-fd0e-11dc-95ff-0800200c9a66}")
  81.                     abp.init();
  82.                 break;
  83.             case "quit-application":
  84.                 abp.shutdown();
  85.                 break;
  86.         }
  87.     }
  88. };
  89.  
  90. /**
  91.  * Adblock Plus XPCOM component
  92.  * @class
  93.  */
  94. const abp =
  95. {
  96.     classDescription: "Adblock Plus component",
  97.     classID: Components.ID("{259c2980-505f-11de-8a39-0800200c9a66}"),
  98.     contractID: "@mozilla.org/adblockplus;1",
  99.     _xpcom_factory: {
  100.         createInstance: function(outer, iid)
  101.         {
  102.             if (outer)
  103.                 throw Cr.NS_ERROR_NO_AGGREGATION;
  104.  
  105.             return abp.QueryInterface(iid);
  106.         }
  107.     },
  108.     _xpcom_categories: [{category: "content-policy"}, {category: "net-channel-event-sinks"}],
  109.  
  110.     //
  111.     // nsISupports interface implementation
  112.     //
  113.  
  114.     QueryInterface: function(iid)
  115.     {
  116.         // Note: do not use |this| in this method! It is being used in the
  117.         // content policy component as well.
  118.  
  119.         if (iid.equals(Ci.nsIContentPolicy) || iid.equals(Ci.nsIChannelEventSink))
  120.             return policy;
  121.  
  122.         if (iid.equals(Ci.nsISupports))
  123.             return abp;
  124.  
  125.         throw Cr.NS_ERROR_NO_INTERFACE;
  126.     },
  127.  
  128.     //
  129.     // IAdblockPlus interface implementation
  130.     //
  131.  
  132.     /**
  133.      * Returns current subscription count
  134.      * @type Integer
  135.      */
  136.     get subscriptionCount()
  137.     {
  138.         return filterStorage.subscriptions.length;
  139.     },
  140.  
  141.     /**
  142.      * Wraps a subscription into IAdblockPlusSubscription structure.
  143.      */
  144.     _getSubscriptionWrapper: function(/**Subscription*/ subscription) /**IAdblockPlusSubscription*/
  145.     {
  146.         if (!subscription)
  147.             return null;
  148.  
  149.         return {
  150.             url: subscription.url,
  151.             special: subscription instanceof SpecialSubscription,
  152.             title: subscription.title,
  153.             autoDownload: subscription instanceof DownloadableSubscription && subscription.autoDownload,
  154.             disabled: subscription.disabled,
  155.             external: subscription instanceof ExternalSubscription,
  156.             lastDownload: subscription instanceof RegularSubscription ? subscription.lastDownload : 0,
  157.             downloadStatus: subscription instanceof DownloadableSubscription ? subscription.downloadStatus : "synchronize_ok",
  158.             lastModified: subscription instanceof DownloadableSubscription ? subscription.lastModified : null,
  159.             expires: subscription instanceof DownloadableSubscription ? subscription.expires : 0,
  160.             getPatterns: function(length)
  161.             {
  162.                 let result = subscription.filters.map(function(filter)
  163.                 {
  164.                     return filter.text;
  165.                 });
  166.                 if (typeof length == "object")
  167.                     length.value = result.length;
  168.                 return result;
  169.             }
  170.         };
  171.     },
  172.  
  173.     /**
  174.      * Gets a subscription by its URL
  175.      */
  176.     getSubscription: function(/**String*/ id) /**IAdblockPlusSubscription*/
  177.     {
  178.         if (id in filterStorage.knownSubscriptions)
  179.             return this._getSubscriptionWrapper(filterStorage.knownSubscriptions[id]);
  180.  
  181.         return null;
  182.     },
  183.  
  184.     /**
  185.      * Gets a subscription by its position in the list
  186.      */
  187.     getSubscriptionAt: function(/**Integer*/ index) /**IAdblockPlusSubscription*/
  188.     {
  189.         if (index < 0 || index >= filterStorage.subscriptions.length)
  190.             return null;
  191.  
  192.         return this._getSubscriptionWrapper(filterStorage.subscriptions[index]);
  193.     },
  194.  
  195.     /**
  196.      * Updates an external subscription and creates it if necessary
  197.      */
  198.     updateExternalSubscription: function(/**String*/ id, /**String*/ title, /**Array of Filter*/ filters, /**Integer*/ length) /**Boolean*/
  199.     {
  200.         if (id == "Filterset.G" && this.denyFiltersetG)
  201.             return false;
  202.  
  203.         try
  204.         {
  205.             // Don't allow valid URLs as IDs for external subscriptions
  206.             if (ioService.newURI(id, null, null))
  207.                 return false;
  208.         } catch (e) {}
  209.  
  210.         let subscription = Subscription.fromURL(id);
  211.         if (!subscription)
  212.             subscription = new ExternalSubscription(id, title);
  213.  
  214.         if (!(subscription instanceof ExternalSubscription))
  215.             return false;
  216.  
  217.         subscription.lastDownload = parseInt(new Date().getTime() / 1000);
  218.  
  219.         let newFilters = [];
  220.         for each (let filter in filters)
  221.         {
  222.             filter = Filter.fromText(normalizeFilter(filter));
  223.             if (filter)
  224.                 newFilters.push(filter);
  225.         }
  226.  
  227.         if (id in filterStorage.knownSubscriptions)
  228.             filterStorage.updateSubscriptionFilters(subscription, newFilters);
  229.         else
  230.         {
  231.             subscription.filters = newFilters;
  232.             filterStorage.addSubscription(subscription);
  233.         }
  234.         filterStorage.saveToDisk();
  235.  
  236.         return true;
  237.     },
  238.  
  239.     /**
  240.      * Removes an external subscription by its identifier
  241.      */
  242.     removeExternalSubscription: function(/**String*/ id) /**Boolean*/
  243.     {
  244.         if (!(id in filterStorage.knownSubscriptions && filterStorage.knownSubscriptions[id] instanceof ExternalSubscription))
  245.             return false;
  246.  
  247.         filterStorage.removeSubscription(filterStorage.knownSubscriptions[id]);
  248.         return true;
  249.     },
  250.  
  251.     /**
  252.      * Adds user-defined filters to the list
  253.      */
  254.     addPatterns: function(/**Array of String*/ filters, /**Integer*/ length)
  255.     {
  256.         for each (let filter in filters)
  257.         {
  258.             filter = Filter.fromText(normalizeFilter(filter));
  259.             if (filter)
  260.                 filterStorage.addFilter(filter);
  261.         }
  262.         filterStorage.saveToDisk();
  263.     },
  264.  
  265.     /**
  266.      * Removes user-defined filters from the list
  267.      */
  268.     removePatterns: function(/**Array of String*/ filters, /**Integer*/ length)
  269.     {
  270.         for each (let filter in filters)
  271.         {
  272.             filter = Filter.fromText(normalizeFilter(filter));
  273.             if (filter)
  274.                 filterStorage.removeFilter(filter);
  275.         }
  276.         filterStorage.saveToDisk();
  277.     },
  278.  
  279.     /**
  280.      * Returns installed Adblock Plus version
  281.      */
  282.     getInstalledVersion: function() /**String*/
  283.     {
  284.         return "1.1.3";
  285.     },
  286.  
  287.     /**
  288.      * Returns source code revision this Adblock Plus build was created from (if available)
  289.      */
  290.     getInstalledBuild: function() /**String*/
  291.     {
  292.         return "428b046a1a26";
  293.     },
  294.  
  295.     //
  296.     // Custom methods
  297.     //
  298.  
  299.     /**
  300.      * Will be set to true if init() was called already.
  301.      * @type Boolean
  302.      */
  303.     initialized: false,
  304.  
  305.     /**
  306.      * If true, incoming updates for Filterset.G should be rejected.
  307.      * @type Boolean
  308.      */
  309.     denyFiltersetG: false,
  310.  
  311.     /**
  312.      * Version comparator instance.
  313.      * @type nsIVersionComparator
  314.      */
  315.     versionComparator: versionComparator,
  316.  
  317.     /**
  318.      * Initializes the component, called on application startup.
  319.      */
  320.     init: function()
  321.     {
  322.  
  323.  
  324.         if (this.initialized)
  325.             return;
  326.         this.initialized = true;
  327.  
  328.  
  329.         prefs.init();
  330.  
  331.  
  332.         filterListener.init();
  333.  
  334.  
  335.         filterStorage.init();
  336.  
  337.  
  338.         policy.init();
  339.  
  340.  
  341.         elemhide.init();
  342.  
  343.  
  344.         synchronizer.init();
  345.  
  346.  
  347.     },
  348.  
  349.     /**
  350.      * Saves all unsaved changes, called on application shutdown.
  351.      */
  352.     shutdown: function()
  353.     {
  354.         filterStorage.saveToDisk();
  355.         prefs.shutdown();
  356.     },
  357.  
  358.     /**
  359.      * Adds a new subscription to the list or changes the parameters of
  360.      * an existing filter subscription.
  361.      */
  362.     addSubscription: function(/**String*/ url, /**String*/ title, /**Boolean*/ autoDownload, /**Boolean*/ disabled)
  363.     {
  364.         if (typeof autoDownload == "undefined")
  365.             autoDownload = true;
  366.         if (typeof disabled == "undefined")
  367.             disabled = false;
  368.  
  369.         let subscription = Subscription.fromURL(url);
  370.         if (!subscription)
  371.             return;
  372.  
  373.         filterStorage.addSubscription(subscription);
  374.  
  375.         if (disabled != subscription.disabled)
  376.         {
  377.             subscription.disabled = disabled;
  378.             filterStorage.triggerSubscriptionObservers(disabled ? "disable" : "enable", [subscription]);
  379.         }
  380.  
  381.         subscription.title = title;
  382.         if (subscription instanceof DownloadableSubscription)
  383.             subscription.autoDownload = autoDownload;
  384.         filterStorage.triggerSubscriptionObservers("updateinfo", [subscription]);
  385.  
  386.         if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
  387.             synchronizer.execute(subscription);
  388.         filterStorage.saveToDisk();
  389.     },
  390.  
  391.     /**
  392.      * Opens preferences dialog or focused already open dialog.
  393.      * @param {String} location  (optional) filter suggestion
  394.      * @param {Filter} filter    (optional) filter to be selected
  395.      */
  396.     openSettingsDialog: function(location, filter)
  397.     {
  398.         var dlg = windowMediator.getMostRecentWindow("abp:settings");
  399.         var func = function()
  400.         {
  401.             if (typeof location == "string")
  402.                 dlg.setLocation(location);
  403.             if (filter instanceof Filter)
  404.                 dlg.selectFilter(filter);
  405.         }
  406.  
  407.         if (dlg)
  408.         {
  409.             func();
  410.  
  411.             try
  412.             {
  413.                 dlg.focus();
  414.             }
  415.             catch (e)
  416.             {
  417.                 // There must be some modal dialog open
  418.                 dlg = windowMediator.getMostRecentWindow("abp:subscription") || windowMediator.getMostRecentWindow("abp:about");
  419.                 if (dlg)
  420.                     dlg.focus();
  421.             }
  422.         }
  423.         else
  424.         {
  425.             dlg = windowWatcher.openWindow(null, "chrome://adblockplus/content/ui/settings.xul", "_blank", "chrome,centerscreen,resizable,dialog=no", null);
  426.             dlg.addEventListener("post-load", func, false);
  427.         }
  428.     },
  429.  
  430.     /**
  431.      * Opens a URL in the browser window. If browser window isn't passed as parameter,
  432.      * this function attempts to find a browser window.
  433.      */
  434.     loadInBrowser: function(/**String*/ url, /**Window*/ currentWindow)
  435.     {
  436.         currentWindow = currentWindow ||
  437.                                         windowMediator.getMostRecentWindow("navigator:browser") ||
  438.                                         windowMediator.getMostRecentWindow("Songbird:Main") ||
  439.                                         windowMediator.getMostRecentWindow("emusic:window");
  440.         let abpHooks = currentWindow ? currentWindow.document.getElementById("abp-hooks") : null;
  441.         if (!abpHooks || !abpHooks.addTab || abpHooks.addTab(url) === false)
  442.         {
  443.             let protocolService = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
  444.             protocolService.loadURI(makeURL(url), null);
  445.         }
  446.     },
  447.  
  448.     params: null,
  449.  
  450.     /**
  451.      * Saves sidebar state before detaching/reattaching
  452.      */
  453.     setParams: function(params)
  454.     {
  455.         this.params = params;
  456.     },
  457.  
  458.     /**
  459.      * Retrieves and removes sidebar state after detaching/reattaching
  460.      */
  461.     getParams: function()
  462.     {
  463.         var ret = this.params;
  464.         this.params = null;
  465.         return ret;
  466.     },
  467.  
  468.     headerParser: headerParser
  469. };
  470. abp.wrappedJSObject = abp;
  471.  
  472. /*
  473.  * Module declaration
  474.  */
  475. function ABPComponent() {}
  476. ABPComponent.prototype = abp;
  477. var NSGetModule = XPCOMUtils.generateNSGetModule([Initializer, ABPComponent]);
  478.  
  479. /*
  480.  * Loading additional files
  481.  */
  482. loader.loadSubScript('chrome://adblockplus/content/utils.js');
  483. loader.loadSubScript('chrome://adblockplus/content/filterClasses.js');
  484. loader.loadSubScript('chrome://adblockplus/content/subscriptionClasses.js');
  485. loader.loadSubScript('chrome://adblockplus/content/filterStorage.js');
  486. loader.loadSubScript('chrome://adblockplus/content/matcher.js');
  487. loader.loadSubScript('chrome://adblockplus/content/elemhide.js');
  488. loader.loadSubScript('chrome://adblockplus/content/filterListener.js');
  489. loader.loadSubScript('chrome://adblockplus/content/policy.js');
  490. loader.loadSubScript('chrome://adblockplus/content/requests.js');
  491. loader.loadSubScript('chrome://adblockplus/content/prefs.js');
  492. loader.loadSubScript('chrome://adblockplus/content/synchronizer.js');
  493.  
  494. /*
  495.  * Core Routines
  496.  */
  497.  
  498. /**
  499.  * Time logging module, used to measure startup time of Adblock Plus (development builds only).
  500.  * @class
  501.  */
  502. var timeLine = {
  503.     _nestingCounter: 0,
  504.     _lastTimeStamp: null,
  505.  
  506.     /**
  507.      * Logs an event to console together with the time it took to get there.
  508.      */
  509.     log: function(/**String*/ message, /**Boolean*/ _forceDisplay)
  510.     {
  511.         if (!_forceDisplay && this._invocationCounter <= 0)
  512.             return;
  513.  
  514.         let now = (new Date()).getTime();
  515.         let diff = this._lastTimeStamp ? (now - this._lastTimeStamp) : "first event";
  516.         this._lastTimeStamp = now;
  517.  
  518.         // Indent message depending on current nesting level
  519.         for (let i = 0; i < this._nestingCounter; i++)
  520.             message = "* " + message;
  521.  
  522.         // Pad message with spaces
  523.         let padding = [];
  524.         for (let i = message.toString().length; i < 40; i++)
  525.             padding.push(" ");
  526.         dump("ABP timeline: " + message + padding.join("") + "\t (" + diff + ")\n");
  527.     },
  528.  
  529.     /**
  530.      * Called to indicate that application entered a block that needs to be timed.
  531.      */
  532.     enter: function(/**String*/ message)
  533.     {
  534.         this.log(message, true);
  535.         this._nestingCounter = (this._nestingCounter <= 0 ? 1 : this._nestingCounter + 1);
  536.     },
  537.  
  538.     /**
  539.  
  540.      */
  541.     leave: function(/**String*/ message)
  542.     {
  543.         this._nestingCounter--;
  544.         this.log(message, true);
  545.  
  546.         if (this._nestingCounter <= 0)
  547.             this._lastTimeStamp = null;
  548.     }
  549. };
  550.